import UIKit
//swfit包含了C和oc上所有的基础数据类型。Int表示整型值；Double和Float表示浮点型；Bool表示布尔型；String表示文本型数据。Array和Dictionary表示数组和字典，就是最基本的两个集合类型。
//如果你需要处理的值不需要改变，那使用常量可以让你的代码更加安全并且更清晰表达你的用途。
//Swift还增加了OC中没有的高阶数据类型比如元组。元组可以让你创建或传递一组数据，比如作为函数的返回值时，可以用一个元组返回多个值。
//Swift还增加了可选Optional类型，用于处理值缺失的情况。
//Swift一门类型安全的的语音。可选类型就是一个很好的例子。

//常量和变量
//常量和变量把一个名字和指定类型的值关联起来。常量的值一旦设定就不能改变，而变量的值可以随意改变。

//声明常量和变量,let 来声明常量， var 来声明变量
let maxinumNumberOfLoginAttempts = 10
var currentLoginAttemps = 0
//在这个例子中，允许的最大尝试登录次数被声明为一个常量，因为这个值不会改变。当前尝试登录次数被声明为一个变量，因为每次尝试登录失败的时候都需要增加这个值。
//你可以在一行中声明多个常量或者多个变量。用逗号隔开
var x = 0.0, y = 0.0, z = 0.0
//注意，如果你的代码有不需要改变的值，请时候用let关键字将它声明为常量。只将需要改变的值声明为变量。

//类型标注
//当你声明常量或者变量时可以加上类型标注。说明常量或者变量要存储的值的类型。如果要添加类型标注，需要在常量或者变量后面加上一个冒号和空格，然后加上数据类型。
var welcomeMessage: String
//声明中的冒号代表着“是...类型”。
welcomeMessage = "hello"
//注意：一般来说很少需要写类型标注。如果你在声明常量或者变量的时候付了一个初值，Swift可以推断出这个常量或变量的类型。
//常量和变量的命名
//你可以用任意字符作为常量或变量名。包括Unicode字符
let π = 3.14159
let 你好 = "你好世界"
let 🐶 = "dog"
//常量和变量名不能包含数学符号，箭头，保留的Unicode码位，连线与制表符。也不能用数字开头，但是可以在其他地方包含数字
var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonijour！"
// 与变量不同，常量值一旦确定就不能修改，尝试这样做会导致编译器报错
let languageName = "Swift"
//languageName = "Swfit++"
//输出常量和变量
//使用print函数输出当前常量和变量
print(friendlyWelcome)
//Swift使用字符串插值的方式把常量名或变量名当做占位符加入到长字符串中，Swift会用当前的常量或变量值替换这些占位符。将常量或变量放入圆括号中，并在开括号前用使用反斜杠将其转义。
print("The current value of friendlyWelcome is \(friendlyWelcome)")

//注释
//这是一个注释
/**
 这个一个多行注释
 
 //分号
 Swfit不强制要求在每行语句的结尾处使用分号 ;有一种情况必须要用分号，即你打算在同一行内写多条独立的语句。
 */
let cat = "mao"; print(cat)

//整数
//整数就是没有小数部分的数。比如42和-23，整数可以是有符号（正，负，零）或无符号的（正，零）。Swfit提供了8,16,32,64位的有符号的或无符号整数类型。比如8位无符号的整数类型是UInt8，32位有符号的整数类型是Int32。整数类型采用大写命名法。
//整数的范围:max属性来获取类型的最大值，min属性来获取类型的最小值
let maxValue = UInt8.max
let minValue = UInt8.min
//一般来说，你不需要专门指定整数的长度。Swift提供了Int类型，长度与当前平台的原生字长相同。在32位平台上，Int和Int32长度相同，在64位平台,Int和Int64相同。
//UInt。Swift提供了一个特殊的无符号类型UInt,长度和当前平台的原生字长相同。在32位平台上，UInt和UInt32长度相同，在64位平台,UInt和UInt64相同
//注意。尽量不要使用UInt，除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况，最好使用Int，即使你要存储的值已知是非负的。统一使用Int可以提高代码的可复用性，避免不同类型数字之间的转换，并且匹配数字的类型推导。Œ

//浮点数.有小数的部分数字，比如3.14159,0.1和-273.15
//Swift提供了两种有符号浮点数类型。
//1.Double表示64位的浮点数。
//2.Float表示322位浮点数。
//注意。Double类型精度很高，至少有15位，而Float最少只有6位数字。如何选择类型看需要。

//类型安全和类型推断
let meaningOfLine = 42
//Swift可以推断出常量类型是Int，因为你给它赋初值看起来像个整数。

let pi = 3.14159
//Swift推断你想要的是Double。当推断浮点数时，Swift总是会选择Double而不是Float.如果表达式同时出现整数和浮点数。会被推断为Double类型
let anotherPi = 3 + 0.14159

//数值型的字面量
//整数的字面量可以被写着：
//一个十进制的数，没有前缀
//一个二进制的数，前缀是0b
//一个八进制的数，前缀是0o
//一个十六进制的数，前缀是0x
//下面所有整数字面量的十进制值都是17
let decimalInteger = 17
let binaryInteger = 0b1001 //二进制17
let octalIngeger = 0o21 //8进制17
let hexadecimalInteger = 0x11//16进制17

//浮点字面量可以是十进制或者十六进制。浮点数字面量还有一个可选的指数，在十进制浮点数中通过大写或小写的e来指定。在十六进制浮点数中，通过大写或小写的p来指定
//如果一个十进制数的指数为exp,那这个数相当于基数和10^exp乘积比如：1.25e2表示1.25 ✖️ 10^2，等于125.0；1.25e-2表示1.25✖️10^-2，等于0.0125
//如果一个十六进制数的指数为exp,那这个数相当于基数和e^exp的乘积.比如:0xFp2表示15✖️2^2，等于60；0xFp-2表示15✖️2^-2,等于3.75.
//下面的这些浮点数字面量都是等于十进制的12.1875
let decimalDouble = 12.1875
let oneMillion = 1.12875e1
let hexadecimalDouble = 0xC.3p0

//整数型类型的转换
//不同整数类型的变量和常量可以存储不同范围的数字。如果数字超过了常量或变量的可存储范围，编译的时候就会报错,比如下面的两行代码
//let cannotBeNagatvie: UInt8 = -1
//let tooBig: Int8 = Int8.max + 1

//每种整数类型都可以存储不同范围的值，所以你必须根据不同的情况选择使用数值型类型转换。
//要将一种数字类型转换成另一种，你要用当前值类初始化一个期望类型的新数字，这个数字类型就是你的 目标类型。比如下面例子。常量twoThousand是UInt16，然后常量one是UInt8类型。他们不能直接相加，因为它们类型不同。所以要调用UInt16(one)来创建一个新的UInt16数字并用one的值来初始化，然后用跟这个新数字来计算。
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
//重要提醒：SomeType(ofInitialValue)是调用Swift构造器并传入一个初始值的默认方法。在语言内部，UInt16有个构造器，可以接受一个UInt8类型的值，因此这个构造器可以用现有的UInt8来创建一个新的UInt16.注意。你不能转入任意类型的值，只能传入UInt16内部有对应构造器的值。不过你可以扩展现有类型来让他们接收其他类型的值，
//整数和浮点数的转换
//必须显示指定类型
let three = 3
let pointOneFourFiveNine = 0.14159
let pi1 = Double(three) + pointOneFourFiveNine
//浮点数到整数的反向转换同样行。整数类型可以用Double或者Flot类型来初始化,此时，浮点值会被截断。
let integerPi = Int(pi1)

//类型的别名。是给现有的类型定义另一个名字。使用typealias关键字来定义类型别名。定义了类型别名后，你在任何使用原始名的地方使用别名
typealias AudioSample = UInt16

var maxAmplitudeFound = AudioSample.min // 0

//布尔值(Bool)，布尔值是逻辑上的，只能是真或者假。true和false
let orangsAreaOrange = true
let turnipsAreaDelicious = false
//上面两个常量类型会被推断出Bool，因为编译器会根据他们的初值是布尔字面量来进行推断。当你编写条件语句比如if语句时，布尔值非常有用。
if turnipsAreaDelicious {
    print("Mmm, tasty turnips!")
} else {
    print("Eww, turnips ar horrible.")
}

//如果你在使用Bool值的地方使用了非布尔值，swift安全机制会报错。比如下面的报错例子
//let i = 1
//if i {
//
//}
	
//然而，下面的例子是合法的
let i = 1
if i == 1 {
    
}

//元祖（Tuples) 把多个值组合成一个复合值。元祖内的值是任意类型，并不要求相同。
let http404Error = (404 , "Not Found")
//(404 , "Not Found") 元祖把一个Int和String值组合起来表示HTT状态码的两个部分；一个数字和一个人类可读的描述。这个元祖可被描述为一个类型为(Int,String)的元祖。你可以将一个元祖的内容分解为单独的常量和变量，然后可以正常使用它们
let (statusCode,statusMessage) = http404Error
print("The code is \(statusCode)")
print("The mesage is \(statusMessage)")

//如果你只需要一部分元祖值，分解的时候可以把要忽略的部分用下划线（_)标记
let (justTheStatusCode, _) = http404Error
//此外，可以通过下标来访问元祖中的元素。下标从零开始
print("The code is \(http404Error.0)")
print("The message is \(http404Error.1)")
//可以在定义元祖时给单个元素命名,然后可以通过名字来获取这些元素
let http200Status = (statusCode:200 ,descrption:"OK")
http200Status.statusCode
http200Status.descrption
//作为函数返回值时，元祖非常有用。另外作为临时组织值时非常有用，但是不适合创建复杂的数据结构。不是临时使用可以考虑类或者结构体

//可选类型
//使用optional来处理值可能缺失的情况。在C和OC中没有可选类型的概念。最接近是OC的一个特性。一个方 要不返回一个对象要不返回nil.

let possibleNumber = "123"
let isInt: Int? = Int(possibleNumber)
if let isInt {
    print(isInt)
} else {
    print("is a nil value.")
}
//因为Int()可能会失败，所以它返回一个可选类型（optional）Int，而不是Int,一个可选的Int被写作Int?而不是Int。问号暗示包含的值是可选类也就是说可能包含Int值也可能不包含值。
//if 语句已及强制解析
//你可以用if已经来判断一个可选是否包含值。如果可选有值结果是true,如果没有值，返回false.当你确定可选类型有值之后，你可以在可选的名字后面加一个感叹号!
if isInt != nil {
    
} else {
    
}
//可选绑定。使用可选绑定来判断可选类型是否包含值，如果包含就把值赋给给一个临时常量或者变量。可选绑定可以用在if和while语句中来对可选类型的值进行判断并把值赋给一个常量或变量。
if let actualNumber = Int(possibleNumber) {
    print("\(possibleNumber) has an int value of \(actualNumber)")
} else {
    print("\(possibleNumber) could not be converted to an int.")
}

//nil 你可以给可选值赋值为nil，来表示它没有值
var serverResponseCode: Int? = 404
serverResponseCode = nil

//注意，nil不能用于非可选类型常量和变量。如果你代码中有常量或者变量处理值缺失的情况，请把他们声明为可选类型。如果你声明一个可选常量或者变量但是没赋值，他们会自动被设置为nil。Swift中的nil和OC中的nil不是一个概念。在OC中，nil是一个指向不存在对象的指针。在Swift中nil不是指针，它是一个确定的值，表示值缺失。任何类型的可选状态都可以被设置为nil，不只是对象类型。
var surveyAnswer: String?
//隐私解析可选类型。如果能够确定变量一定是有值的，每次都判断和解析可选类型是非常低效的。此时把想要作为可选类型的后面的？改成!来声明一个隐式解析可选类型。
let possString: String? = "An optional string"
print(possString!) //使用感叹号来取值
let assumedString: String! = "An implicity unwrapped optinal string."
print(assumedString!)
if (assumedString != nil) {
    print(assumedString!)
}

if let definiteString = assumedString {
    print(definiteString)
}

//断言。有些情况下，如果值缺失或者值不满足特定的条件，你的代码可能无法执行，这是可以在代码中触发一个断言assetion来结束代码运行并通过调试来找到值缺失的情况。断言来保证运行其他代码之前，某些重要的条件已经满足。如果条件判断为true，代码运行会继续进行，如果条件为false，代码运行停止，你的应用终止。断言允许你附加一条调试信息
//你可以使用全局的assert函数来写一个断言。向assert函数传递一个结果为true或fasle的表达式以及一条信息，当表达式为false的时候这条信息会被现实。
let age = -3
assert(age >= 0, "A person'age cannot bef less than zero.")
//在这个例子当中，只有age>=0为true的时候，即age的值非负的时候，代码才会继续。如果age值为负，断言将会被触发，结束应用。
//何时使用断言。当条件为假的时候使用断言，但是最终一定要保证条件为真，不然你的代码将不会执行。断言的使用场景是：1.整数类型的下标索引被传入一个自定义下标脚本实现，但是下标索引可能太小或太大。2.需要给函数传值，但是传非法值可能导致函数无法运行。3.一个可选值现在是nil，可能后面的代码运行需要一个非nil值。
